#include "rx8130ce.h"
#include "i2c.h"

// RX-8130 Register definitions
#define RX8130_REG_SEC		0x10
#define RX8130_REG_MIN		0x11
#define RX8130_REG_HOUR		0x12
#define RX8130_REG_WDAY		0x13
#define RX8130_REG_MDAY		0x14
#define RX8130_REG_MONTH	0x15
#define RX8130_REG_YEAR		0x16

#define RX8130_REG_ALMIN	0x17
#define RX8130_REG_ALHOUR	0x18
#define RX8130_REG_ALWDAY	0x19
#define RX8130_REG_TCOUNT0	0x1A
#define RX8130_REG_TCOUNT1	0x1B
#define RX8130_REG_EXT		0x1C
#define RX8130_REG_FLAG		0x1D
#define RX8130_REG_CTRL0	0x1E
#define RX8130_REG_CTRL1	0x1F

#define RX8130_REG_END		0x23

// Extension Register (1Ch) bit positions
#define RX8130_BIT_EXT_TSEL		(7 << 0)
#define RX8130_BIT_EXT_WADA		(1 << 3)
#define RX8130_BIT_EXT_TE		(1 << 4)
#define RX8130_BIT_EXT_USEL		(1 << 5)
#define RX8130_BIT_EXT_FSEL		(3 << 6)

// Flag Register (1Dh) bit positions
#define RX8130_BIT_FLAG_VLF		(1 << 1)
#define RX8130_BIT_FLAG_AF		(1 << 3)
#define RX8130_BIT_FLAG_TF		(1 << 4)
#define RX8130_BIT_FLAG_UF		(1 << 5)

// Control 0 Register (1Еh) bit positions
#define RX8130_BIT_CTRL_TSTP	(1 << 2)
#define RX8130_BIT_CTRL_AIE		(1 << 3)
#define RX8130_BIT_CTRL_TIE		(1 << 4)
#define RX8130_BIT_CTRL_UIE		(1 << 5)
#define RX8130_BIT_CTRL_STOP	(1 << 6)
#define RX8130_BIT_CTRL_TEST	(1 << 7)

// Control 1 Register (1Fh) bit positions
#define RX8130_BIT_CTRL_INIEN	(1 << 4)
#define RX8130_BIT_CTRL_CHGEN	(1 << 5)

static uint8_t rx8130ce_bcd2bin(uint8_t bcd) {
    return (10 * (bcd >> 4)) + (bcd & 0x0F);
}

static uint8_t rx8130ce_bin2bcd(uint8_t bin) {
    return ((bin / 10) << 4) | (bin % 10);
}

void rx8130ce_init(void) {
    i2c_config();
}

int rx8130ce_set_time(const rx8130ce_time_t *buf) {
    uint8_t rtc_ctrl;
    
    // enable battery switch
    i2c_byte_read(RX8130_SLAVE_ADDR, RX8130_REG_CTRL1, &rtc_ctrl);
	rtc_ctrl = rtc_ctrl | RX8130_BIT_CTRL_INIEN; //| RX8130_BIT_CTRL_CHGEN;
    i2c_byte_write(RX8130_SLAVE_ADDR, RX8130_REG_CTRL1, rtc_ctrl);

    //set STOP bit before changing clock/calendar
    i2c_byte_read(RX8130_SLAVE_ADDR, RX8130_REG_CTRL0, &rtc_ctrl);
	rtc_ctrl = rtc_ctrl | RX8130_BIT_CTRL_STOP;
    i2c_byte_write(RX8130_SLAVE_ADDR, RX8130_REG_CTRL0, rtc_ctrl);
	
    uint8_t time_data[7];
    time_data[6] = rx8130ce_bin2bcd(buf->year % 100);
    time_data[5] = rx8130ce_bin2bcd(buf->month);
    time_data[4] = rx8130ce_bin2bcd(buf->day);
    time_data[3] = 1<<(buf->week);
    time_data[2] = rx8130ce_bin2bcd(buf->hours);
    time_data[1] = rx8130ce_bin2bcd(buf->minutes);
    time_data[0] = rx8130ce_bin2bcd(buf->seconds);
        
    i2c_buffer_write(RX8130_SLAVE_ADDR, RX8130_REG_SEC, time_data, 7);

	//clear STOP bit after changing clock/calendar
    i2c_byte_read(RX8130_SLAVE_ADDR, RX8130_REG_CTRL0, &rtc_ctrl);
    rtc_ctrl = rtc_ctrl & ~RX8130_BIT_CTRL_STOP;
    i2c_byte_write(RX8130_SLAVE_ADDR, RX8130_REG_CTRL0, rtc_ctrl);

    return 0;
}

int rx8130ce_get_time(rx8130ce_time_t *buf) {
    uint8_t time_data[7];
    i2c_buffer_read(RX8130_SLAVE_ADDR, RX8130_REG_SEC, time_data, 7);
    
    buf->year = rx8130ce_bcd2bin(time_data[6]), 
    buf->month = rx8130ce_bcd2bin(time_data[5]), 
    buf->day = rx8130ce_bcd2bin(time_data[4]), 
    buf->hours = rx8130ce_bcd2bin(time_data[2]), 
    buf->minutes = rx8130ce_bcd2bin(time_data[1]), 
    buf->seconds = rx8130ce_bcd2bin(time_data[0]), 
    //buf->week = rx8130ce_bcd2bin(time_data[3]);
    buf->week = 0;
    while ((time_data[3] & 1) == 0) {
        buf->week++;
        time_data[3] >>= 1;
    }

    return 0;
}
